package com.example.concurrentprogramming8016.future.forkjoin.arraysum;

import com.example.concurrentprogramming8016.future.forkjoin.ArrayUtils;

import java.util.concurrent.*;

/**
 * @author liyanhao
 * @Date 2023-01-08 9:45
 * 进行递归Task调用
 */
public class SumRecursiveMT {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        int[] array = ArrayUtils.buildRandomIntArray(100000000);
            ExecutorService threadPool1 = Executors.newFixedThreadPool(100);
        long start1 = System.currentTimeMillis();
        long sum1 = SumMultiThreads.sum(array, threadPool1);
        System.out.println(sum1);
        threadPool1.shutdown();
        long end1 = System.currentTimeMillis();
        System.out.println(end1 - start1);

        ExecutorService threadPool = Executors.newFixedThreadPool(10);
        long start2= System.currentTimeMillis();
        SumTask2 sumTask2 = new SumTask2(array, 0, array.length, threadPool);
        Future<Long> submit = threadPool.submit(sumTask2);
        long end2 = System.currentTimeMillis();
        Long result = submit.get();
        System.out.println(result);
        threadPool.shutdown();
        System.out.println(end2 - start2);
    }
}

class SumTask2 implements Callable<Long> {

    //拆分最小粒度
    public static final int SEQUENTIAL_CUTOFF = 100000;
    int[] arr;
    int start;
    int end;
    ExecutorService executorService;

    public SumTask2(int[] arr, int start, int end, ExecutorService executorService) {
        this.arr = arr;
        this.start = start;
        this.end = end;
        this.executorService = executorService;
    }

    @Override
    public Long call() throws Exception {
  /*      System.out.format("%s range [%d-%d] begin to compute %n",
                Thread.currentThread().getName(), start, end);*/
        long result = 0;
        if (end - start <= SEQUENTIAL_CUTOFF) {
            for (int i = start; i < end; i++) {
                result += arr[i];
            }
        } else {
            SumTask2 taskLeft = new SumTask2(arr, start, (start + end) / 2, executorService);
            SumTask2 taskRight = new SumTask2(arr, (start + end) / 2, end, executorService);
            result = executorService.submit(taskLeft).get()
                    + executorService.submit(taskRight).get();
        }
        return result;
    }
}
